 /*******************************************************************************
  * Copyright (c) 2006, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.core.databinding.observable;

 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.ListenerList;

 /**
  * Listener management implementation. Exposed to subclasses in form of
  * {@link AbstractObservable} and {@link ChangeSupport}.
  *
  * @since 1.0
  *
  */
 /* package */ class ChangeManager {

     ListenerList[] listenerLists = null;
     Object listenerTypes[] = null;
     private Realm realm;

     /**
      * @param realm
      *
      */
     /* package */ ChangeManager(Realm realm) {
         Assert.isNotNull(realm);
         this.realm = realm;
     }

     /**
      * @param listenerType
      * @param listener
      */
     protected void addListener(Object listenerType,
             IObservablesListener listener) {
         int listenerTypeIndex = findListenerTypeIndex(listenerType);
         if (listenerTypeIndex == -1) {
             int length;
             if (listenerTypes == null) {
                 length = 0;
                 listenerTypes = new Object [1];
                 listenerLists = new ListenerList[1];
             } else {
                 length = listenerTypes.length;
                 System.arraycopy(listenerTypes, 0,
                         listenerTypes = new Object [length + 1], 0, length);
                 System
                         .arraycopy(listenerLists, 0,
                                 listenerLists = new ListenerList[length + 1],
                                 0, length);
             }
             listenerTypes[length] = listenerType;
             listenerLists[length] = new ListenerList();
             boolean hadListeners = hasListeners();
             listenerLists[length].add(listener);
             if (!hadListeners) {
                 this.firstListenerAdded();
             }
             return;
         }
         ListenerList listenerList = listenerLists[listenerTypeIndex];
         boolean hadListeners = true;
         if (listenerList.size() == 0) {
             hadListeners = hasListeners();
         }
         listenerList.add(listener);
         if (!hadListeners) {
             firstListenerAdded();
         }
     }

     /**
      * @param listenerType
      * @param listener
      */
     protected void removeListener(Object listenerType,
             IObservablesListener listener) {
         int listenerTypeIndex = findListenerTypeIndex(listenerType);
         if (listenerTypeIndex != -1) {
             listenerLists[listenerTypeIndex].remove(listener);
             if (listenerLists[listenerTypeIndex].size() == 0) {
                 if (!hasListeners()) {
                     this.lastListenerRemoved();
                 }
             }
         }
     }

     protected boolean hasListeners() {
         if (listenerTypes == null) {
             return false;
         }
         for (int i = 0; i < listenerTypes.length; i++) {
             if (listenerLists[i].size() > 0) {
                 return true;
             }
         }
         return false;
     }

     private int findListenerTypeIndex(Object listenerType) {
         if (listenerTypes != null) {
             for (int i = 0; i < listenerTypes.length; i++) {
                 if (listenerTypes[i] == listenerType) {
                     return i;
                 }
             }
         }
         return -1;
     }

     protected void fireEvent(ObservableEvent event) {
         Object listenerType = event.getListenerType();
         int listenerTypeIndex = findListenerTypeIndex(listenerType);
         if (listenerTypeIndex != -1) {
             Object [] listeners = listenerLists[listenerTypeIndex]
                     .getListeners();
             for (int i = 0; i < listeners.length; i++) {
                 event.dispatch((IObservablesListener) listeners[i]);
             }
         }
     }

     /**
      *
      */
     protected void firstListenerAdded() {
     }

     /**
      *
      */
     protected void lastListenerRemoved() {
     }

     /**
      *
      */
     public void dispose() {
         listenerLists = null;
         listenerTypes = null;
         realm = null;
     }

     /**
      * @return Returns the realm.
      */
     public Realm getRealm() {
         return realm;
     }

 }

